/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * GameLoaderFrame.java
 *
 * Created on 17/05/2011, 21:04:45
 */
package GUI.GameLoadWindowPackage;

import GUI.PopUpDialog;
import GameServer.ServerService;
import Monopol.Events.RefreshMonopolyGames;
import Monopol.MonopolExceptions.MonopolErrors;
import Utils.GameDetails;
import Utils.LoadInfo;
import Utils.Utils;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

/**
 *
 * @author Assaf
 */
public class GameLoaderFrame extends javax.swing.JFrame {

    private ListSelectionModel listSelectionModel;
    private LoadInfo[] arrPlayers = new LoadInfo[6];
    private Boolean finished = false;
    private Integer playerID = -1;
    private Boolean bAutoDice;
    private Boolean defDiceMode;
    private Timer gamesRefreshTimer;
    private CountDownLatch closeSignal;
    // String Constants
    private final String JOIN_GAME = "Start the Game!";
    private final String CREATE_GAME = "Create a Game!";
    private Timer waitForGames;
    private String playerName;

    /** Creates new form GameLoaderFrame */
    public GameLoaderFrame(String defServerName, Integer defServerPort, String defPlayerName, Boolean defDiceMode) {
	// Set the OS Default Look and Feel
	Utils.setLookAndFeel();
	// Initialize the Rest of the Components and Add them to the Frame
	initComponents();
	// Set the Defaults Paramters
	txtServerName.setText(defServerName);
	txtSrvPort.setText(defServerPort.toString());
	txtDefPlayerName.setText(defPlayerName);
	chkAutoDice.setSelected(defDiceMode);
	this.defDiceMode = defDiceMode;
	if (defDiceMode) {
	    // Select the Automatic Dice Roll
	    cbDefDiceMode.setSelectedIndex(0);
	} else {
	    // Select the Manual Dice Roll
	    cbDefDiceMode.setSelectedIndex(1);
	}
	// Centering the window
	this.setBounds(Utils.posCenterScreen(getWidth(), getHeight()));
	setLocationRelativeTo(null);
	// Start a Refresh Task for the Games
	startRefreshTask();
	// Pack the Frame with the Desired Width and Heigth
	pack();
	// Add a Listener for the Tabbed Pane
	addTabListener();
	// Set the Default Players Name
	txtPlayerName.setText(txtDefPlayerName.getText().replace("#", String.valueOf(arrPlayers.length + 1)));
    }

    /**
     * Show this Frame
     */
    public Boolean showLoadWindow(CountDownLatch cntDown) {
	if (closeSignal == null) {
	    closeSignal = cntDown;
	}
	// Show the Load Window
	setVisible(true);
	// Returned only after this Frame is no longer Visible
	return finished;
    }

    /**
     * Starts a Monopoly Game Refresh Task
     */
    private void startRefreshTask() {
	gamesRefreshTimer = ServerService.getInstance().startPolling("Waiting Games Timer", new RefreshMonopolyGames(this), 0, 5);
    }

    /**
     * Stops the Monopoly Game Refresh Task
     */
    private void stopRefreshTask() {
	if (gamesRefreshTimer != null) {
	    gamesRefreshTimer.cancel();
	}
	finished = true;
    }

    private void startWaitingToJoin(String gameName, Integer playerUID) {
	waitForGames = ServerService.getInstance().startPolling("Waiting to Join a Game", new WaitForGameToStart(this, gameName, playerUID), 0, 5);
    }

    private void stopWaitingToJoin() {
	if (waitForGames != null) {
	    waitForGames.cancel();
	}
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        tabPanel = new javax.swing.JTabbedPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        tblGames = new javax.swing.JTable();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        txtGameName = new javax.swing.JTextField();
        chkAutoDice = new javax.swing.JCheckBox();
        sldNumOfPlayers = new javax.swing.JSlider();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        sldNumOfHumans = new javax.swing.JSlider();
        txtPlayerName = new javax.swing.JTextField();
        jLabel4 = new javax.swing.JLabel();
        jLabel9 = new javax.swing.JLabel();
        lblHumanTicks = new javax.swing.JLabel();
        jPanel2 = new javax.swing.JPanel();
        jLabel6 = new javax.swing.JLabel();
        txtServerName = new javax.swing.JTextField();
        jLabel7 = new javax.swing.JLabel();
        txtDefPlayerName = new javax.swing.JTextField();
        btnSaveSettings = new javax.swing.JButton();
        cbDefDiceMode = new javax.swing.JComboBox();
        jLabel8 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        txtSrvPort = new javax.swing.JTextField();
        lblHeader = new javax.swing.JLabel();
        pnlGameDetails = new javax.swing.JPanel();
        lblGameDetails = new javax.swing.JLabel();
        btnCreateStart = new javax.swing.JButton();
        btnExit = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        tblGames.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Name", "Num. Of Players", "Num. Of Humans Joined"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.Integer.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        tblGames.setColumnSelectionAllowed(true);
        tblGames.getTableHeader().setReorderingAllowed(false);
        tblGames.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                tblGamesPropertyChange(evt);
            }
        });
        jScrollPane1.setViewportView(tblGames);
        tblGames.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);

        tabPanel.addTab("Join a Game", jScrollPane1);

        jPanel1.setPreferredSize(new java.awt.Dimension(400, 250));

        jLabel1.setText("Game Name:");

        chkAutoDice.setSelected(true);
        chkAutoDice.setText("Automatic Roll Dice Mode");

        sldNumOfPlayers.setMaximum(6);
        sldNumOfPlayers.setMinimum(2);
        sldNumOfPlayers.setMinorTickSpacing(1);
        sldNumOfPlayers.setPaintLabels(true);
        sldNumOfPlayers.setPaintTicks(true);
        sldNumOfPlayers.setSnapToTicks(true);
        sldNumOfPlayers.setToolTipText("Total number of Players");
        sldNumOfPlayers.setValue(2);
        sldNumOfPlayers.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sldNumOfPlayersStateChanged(evt);
            }
        });

        jLabel2.setFont(new java.awt.Font("Tahoma", 0, 14));
        jLabel2.setText("Choose the Total Number of Players");

        jLabel3.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        jLabel3.setText("Choose the Number of Human Players");

        sldNumOfHumans.setMaximum(2);
        sldNumOfHumans.setMinimum(1);
        sldNumOfHumans.setMinorTickSpacing(1);
        sldNumOfHumans.setPaintLabels(true);
        sldNumOfHumans.setPaintTicks(true);
        sldNumOfHumans.setSnapToTicks(true);
        sldNumOfHumans.setToolTipText("Total number of Human Players");
        sldNumOfHumans.setValue(1);

        txtPlayerName.setText("Player 1");
        txtPlayerName.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                txtPlayerNameActionPerformed(evt);
            }
        });
        txtPlayerName.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                txtPlayerNameFocusGained(evt);
            }
        });

        jLabel4.setText("Player Name:");

        jLabel9.setText("  2---------------------3---------------------4---------------------5---------------------6");

        lblHumanTicks.setText("  1----------------------------------------------------------------------------------------2");

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
                                .addComponent(jLabel4)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(txtPlayerName, javax.swing.GroupLayout.PREFERRED_SIZE, 125, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 35, Short.MAX_VALUE)
                                .addComponent(chkAutoDice))
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
                                .addComponent(jLabel1)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(txtGameName, javax.swing.GroupLayout.PREFERRED_SIZE, 308, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(sldNumOfPlayers, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 373, Short.MAX_VALUE))
                        .addGap(70, 70, 70))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel3)
                        .addContainerGap(153, Short.MAX_VALUE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel9)
                        .addContainerGap(15, Short.MAX_VALUE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(sldNumOfHumans, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(lblHumanTicks, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap(17, Short.MAX_VALUE))))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(txtGameName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel4)
                    .addComponent(chkAutoDice)
                    .addComponent(txtPlayerName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(14, 14, 14)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(sldNumOfPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(4, 4, 4)
                .addComponent(jLabel9)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(sldNumOfHumans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(lblHumanTicks)
                .addContainerGap())
        );

        tabPanel.addTab("Create a Game", jPanel1);

        jLabel6.setText("Server Name:");

        txtServerName.setText("LocalHost");

        jLabel7.setText("Default Player Name:");

        txtDefPlayerName.setText("Player #");

        btnSaveSettings.setText("Save Settings");
        btnSaveSettings.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSaveSettingsActionPerformed(evt);
            }
        });

        cbDefDiceMode.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Automatic Dice Roll", "Manul Dice Roll" }));

        jLabel8.setText("Default Dice Mode:");

        jLabel5.setText("Server Port:");

        txtSrvPort.setText("8080");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGap(154, 154, 154)
                        .addComponent(btnSaveSettings))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel6)
                            .addComponent(jLabel7)
                            .addComponent(jLabel8)
                            .addComponent(jLabel5))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(txtSrvPort)
                            .addComponent(txtDefPlayerName)
                            .addComponent(txtServerName, javax.swing.GroupLayout.DEFAULT_SIZE, 251, Short.MAX_VALUE)
                            .addComponent(cbDefDiceMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap(24, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(35, 35, 35)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(txtServerName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(txtSrvPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(12, 12, 12)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel7)
                    .addComponent(txtDefPlayerName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(37, 37, 37)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(cbDefDiceMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel8))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 36, Short.MAX_VALUE)
                .addComponent(btnSaveSettings)
                .addContainerGap())
        );

        tabPanel.addTab("Configuration", jPanel2);

        lblHeader.setFont(new java.awt.Font("Century", 1, 24));
        lblHeader.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/icon.png"))); // NOI18N
        lblHeader.setText("Monopoly Games");

        pnlGameDetails.setBorder(new javax.swing.border.MatteBorder(null));
        pnlGameDetails.setMaximumSize(new java.awt.Dimension(225, 243));

        lblGameDetails.setText("No Game Selected");
        lblGameDetails.setVerticalAlignment(javax.swing.SwingConstants.TOP);

        javax.swing.GroupLayout pnlGameDetailsLayout = new javax.swing.GroupLayout(pnlGameDetails);
        pnlGameDetails.setLayout(pnlGameDetailsLayout);
        pnlGameDetailsLayout.setHorizontalGroup(
            pnlGameDetailsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlGameDetailsLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(lblGameDetails, javax.swing.GroupLayout.DEFAULT_SIZE, 203, Short.MAX_VALUE)
                .addContainerGap())
        );
        pnlGameDetailsLayout.setVerticalGroup(
            pnlGameDetailsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlGameDetailsLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(lblGameDetails, javax.swing.GroupLayout.DEFAULT_SIZE, 219, Short.MAX_VALUE)
                .addContainerGap())
        );

        btnCreateStart.setText("Start the Game!");
        btnCreateStart.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnCreateStartActionPerformed(evt);
            }
        });

        btnExit.setText("Exit");
        btnExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnExitActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(73, 73, 73)
                        .addComponent(lblHeader))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(tabPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 402, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(pnlGameDetails, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(126, 126, 126)
                        .addComponent(btnCreateStart)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 361, Short.MAX_VALUE)
                        .addComponent(btnExit)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(14, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(lblHeader)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(tabPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 273, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(pnlGameDetails, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnCreateStart)
                    .addComponent(btnExit))
                .addGap(6, 6, 6))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void btnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExitActionPerformed
	// Close this Frame
	CloseWindow(null, -1, true);
    }//GEN-LAST:event_btnExitActionPerformed

    /**
     * The Action for the Create Game / Join Game Button
     * @param evt The Action Event
     */
    private void btnCreateStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCreateStartActionPerformed
	if (btnCreateStart.getText().equals(JOIN_GAME)) {
	    // Get the Table Model
	    DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	    // Get the Selected Row
	    int selectedRow = tblGames.getSelectedRow();
	    if (selectedRow < 0) {
		selectedRow = 0;
	    }
	    // Get the Game Name from the Selected Row First Column
	    String gameName = (String) model.getValueAt(selectedRow, 0);
	    // Get the Game Details for the elected Game from the Server
	    GameDetails gameDetails = ServerService.getInstance().getGameDetails(gameName);
	    // Verify that the game can be joined
	    if (gameDetails.getGameStatus().toUpperCase().equals("WAITING")) {
		// Check if Player is Not Joined yet
		if (playerID == -1) {
		    // Get the Dice Mode
		    bAutoDice = gameDetails.isAutomaticDiceRoll();
		    // Offer to Input a New Player Name if the Player NAme is Empty
		    if (playerName == null || playerName.isEmpty()) {
			playerName = (String) JOptionPane.showInputDialog(null, "Enter a New Player Name: ",
				"Join a Monopoly Game - Change Player Name", 1, null, null, txtDefPlayerName.getText().replace("#", String.valueOf(arrPlayers.length + 1)));
		    }
		    // Join the Player to the Game in the Server
		    Integer pID = ServerService.getInstance().joinPlayer(gameName, playerName);
		    // Verify that the Player joined the Game
		    // If the Player ID is -1 => This Means Error, Try Setting a Different Player Name
		    while (pID == -1) {
			String newPlayerName = (String) JOptionPane.showInputDialog(null, "Enter a New Player Name: ",
				"Join a Monopoly Game - Change Player Name", 1, null, null, txtDefPlayerName.getText().replace("#", String.valueOf(arrPlayers.length + 1)));
			if (newPlayerName != null) {
			    // Save the Player Name
			    playerName = newPlayerName;
			    // Join the Player to the Game in the Server
			    pID = ServerService.getInstance().joinPlayer(gameName, playerName);
			} else {
			    pID = -1;
			}
		    }
		    // Start Wating to Join the Game
		    startWaitingToJoin(gameName, pID);
		} else {
		    // Show Player Error
		    Utils.showError(this, "You allready Joined this Game!");
		}
	    } else {
		// Show Player Error
		Utils.showError(this, "Can not Join an Active Game");
	    }
	} else if (btnCreateStart.getText().equals(CREATE_GAME)) {
	    // Create a New Array of Players
	    arrPlayers = new LoadInfo[sldNumOfPlayers.getValue()];
	    // Count the Number of Human Players
	    Integer humPlayers = sldNumOfHumans.getValue();
	    // Count the Number of Computer Players
	    Integer compPlayers = sldNumOfPlayers.getValue() - humPlayers;
	    // Update the Game in the Server
	    updateCreatedGame(txtGameName.getText(), humPlayers, compPlayers, chkAutoDice.isSelected());
	    // Change the Text in the Button to Join the Game
	    btnCreateStart.setText(JOIN_GAME);
	    // Save the Player Name
	    playerName = txtPlayerName.getText();
	    // Switch to the Join Game Tab
	    tabPanel.setSelectedIndex(0);
	}

	// Update the Games Table
	getMonopolyGames();

    }//GEN-LAST:event_btnCreateStartActionPerformed

    /**
     * Set the Player Name Text on Focus
     * @param evt The Focus Event
     */
    private void txtPlayerNameFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPlayerNameFocusGained
	// Check that the Player Name is not Empty
	if (txtPlayerName.getText().isEmpty()) {
	    txtPlayerName.setText(txtDefPlayerName.getText().replace("#", String.valueOf(arrPlayers.length + 1)));
	}
    }//GEN-LAST:event_txtPlayerNameFocusGained

    private void txtPlayerNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtPlayerNameActionPerformed
}//GEN-LAST:event_txtPlayerNameActionPerformed

    /**
     * Preform Players Number Slider State Change Action
     * @param evt The Change Event
     */
    private void sldNumOfPlayersStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sldNumOfPlayersStateChanged
	try {
	    JSlider source = (JSlider) evt.getSource();
	    if (!source.getValueIsAdjusting()) {
		sldNumOfHumans.setMaximum(source.getValue());
		switch (source.getValue()) {
		    case 2: {
			lblHumanTicks.setText("  1--------------------------------------------------------------------------------------2");
			break;
		    }
		    case 3: {
			lblHumanTicks.setText("  1-------------------------------------------2-------------------------------------------3");
			break;
		    }
		    case 4: {
			lblHumanTicks.setText("  1----------------------------2-----------------------------3----------------------------4");
			break;
		    }
		    case 5: {
			lblHumanTicks.setText("  1---------------------2---------------------3---------------------4---------------------5");
			break;
		    }
		    case 6: {
			lblHumanTicks.setText("  1----------------2----------------3----------------4-----------------5------------------6");
			break;
		    }
		}
	    }
	} catch (ClassCastException c) {
	    // Not the Class that we were looking for
	}
}//GEN-LAST:event_sldNumOfPlayersStateChanged

    private void tblGamesPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_tblGamesPropertyChange
}//GEN-LAST:event_tblGamesPropertyChange

    private void btnSaveSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSaveSettingsActionPerformed
	// Save the Settings to the Configuration File
	// Get a new Properties Object
	Properties myConfig = new Properties();
	// Get the AppConfig File Path
	URL outConfigPath = getClass().getClassLoader().getResource("resources/appConfig.xml");
	OutputStream outConfig;
	try {
	    // Get the File Output Stream - For Writing
	    outConfig = new FileOutputStream(outConfigPath.getPath());

	    // Save the Properties in the Properties Object
	    myConfig.setProperty("ServerName", txtServerName.getText());
	    myConfig.setProperty("ServerPort", txtSrvPort.getText());
	    myConfig.setProperty("DefaultPlayerName", txtDefPlayerName.getText());
	    if (cbDefDiceMode.getSelectedIndex() == 0) {
		myConfig.setProperty("DefaultDiceRollMode", "Auto");
	    } else {
		myConfig.setProperty("DefaultDiceRollMode", "Man");
	    }
	    // Store the Properties in the AppConfig File
	    myConfig.storeToXML(outConfig, "Monopoly Client Configuration");
	} catch (IOException ex) {
	    Logger.getLogger(GameLoaderFrame.class.getName()).log(Level.SEVERE, null, ex);
	}
    }//GEN-LAST:event_btnSaveSettingsActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
	java.awt.EventQueue.invokeLater(new Runnable() {

	    public void run() {
		new GameLoaderFrame("localhost", 8080, "TestPlayer #", false).setVisible(true);
	    }
	});
    }

    /**
     * Updates the Table about the Current Games in the Server
     */
    public void getMonopolyGames() {
	try {
	    String[] waitingGames = ServerService.getInstance().getWaitingMonopolyGames();
	    String[] activeGames = ServerService.getInstance().getActiveMonopolyGames();
	    // Check if No Waiting Games And there are Active Games
	    if (waitingGames.length == 0 && activeGames.length > 0) {
		// Disable the Create a New Game - Working in One Active Game Only
		tabPanel.setEnabledAt(1, false);
		// Enable the Join Game Tab
		tabPanel.setEnabledAt(0, true);
		// Verify That the Configuration Tab is NOT Selected
		if (tabPanel.getSelectedIndex() != 2) {
		    // Select the Join Game Tab
		    tabPanel.setSelectedIndex(0);
		}
		// Update the Active Games in the Table
		getGames(activeGames);
	    } else if (waitingGames.length > 0 && activeGames.length == 0) {
		// Enable the Join Game Tab
		tabPanel.setEnabledAt(0, true);
		// Disable the Create a New Game - Working in One Active Game Only
		tabPanel.setEnabledAt(1, false);
		// Verify That the Configuration Tab is NOT Selected
		if (tabPanel.getSelectedIndex() != 2) {
		    // Select the Join Game Tab
		    tabPanel.setSelectedIndex(0);
		}
		// Update the Waiting Games in the Table
		getGames(waitingGames);
	    } else {
		// Clear the Table
		clearTable();
		// No Games - Allow Create
		tabPanel.setEnabledAt(1, true);
		// Disable Joining A Game
		tabPanel.setEnabledAt(0, false);
		// Verify That the Configuration Tab is NOT Selected
		if (tabPanel.getSelectedIndex() != 2) {
		    // Select the Create Game Tab
		    tabPanel.setSelectedIndex(1);
		    // Request Focus for the Game Name Text
		    txtGameName.setRequestFocusEnabled(true);
		}
	    }
	} catch (Exception e) {
	    PopUpDialog errDialog = new PopUpDialog(this, "Server Error, Can't get Monopoly Games!", 10);
	    errDialog.showErrorMessage();
	    Logger.getLogger(GameLoader.class.getName()).log(Level.SEVERE, null, e);
	    Utils.writeText("Quiting the Game!");
	    System.exit(1);
	}
    }

    /**
     * Checks if a Game with the input name Exists in the Games Table
     * @param gameName The Game to Search
     * @return Soes the Game Exists in the Table or Not
     */
    private Boolean gameExists(String gameName) {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// For Each Game in the Table
	for (int i = 0; i < model.getRowCount(); ++i) {
	    // Check if the Game Exists in the Table
	    if (model.getValueAt(i, 0).equals(gameName)) {
		// The Game Exists - Return True
		return true;
	    }
	}
	// No Games were found  - Return False
	return false;
    }

    /**
     * Finds the Game Row in the Table
     * @param gameName The Game name to Find
     * @return The Game Row or -1 For Error
     */
    private Integer getGameRow(String gameName) {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// For Each Game in the Table
	for (int i = 0; i < model.getRowCount(); ++i) {
	    // Check if the Game Exists in the Table
	    if (model.getValueAt(i, 0).equals(gameName)) {
		// The Game Exists - Return The Game Row
		return i;
	    }
	}
	// No Games were found  - Return Error (-1)
	return -1;
    }

    /**
     * Updates the Table with Monopoly Games
     * @param monopolyGames The Monopoly Games Names String Array
     */
    private void getGames(String[] monopolyGames) {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// For Each Game in the Monopoly Games
	for (String name : monopolyGames) {
	    // Get the Game Details for the Game
	    GameDetails gameDetails = ServerService.getInstance().getGameDetails(name);
	    // Verify that the Game Doesnt Exists in the TAble Allready
	    if (gameExists(name) == false) {
		// This is a New Game - Add a new Row to the Table
		model.addRow(new Object[]{name, gameDetails.getTotalPlayers(), gameDetails.getJoinedHumans()});
	    } // The Game Exists - Update it
	    else {
		// Remove the Old Game
		model.removeRow(getGameRow(name));
		// Update the Game with the new Details
		model.addRow(new Object[]{name, gameDetails.getTotalPlayers(), gameDetails.getJoinedHumans()});
	    }
	}

	// Set the New Rows
	tblGames.setModel(model);
	listSelectionModel = tblGames.getSelectionModel();
	listSelectionModel.addListSelectionListener(new TableListSelectionHandler());
	tblGames.setSelectionModel(listSelectionModel);
    }

    /**
     * Clears the Table of Games
     */
    private void clearTable() {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// Loop on all the Rows
	for (int i = 0; i < model.getRowCount(); ++i) {
	    // Remove the Row from the Table Model
	    model.removeRow(i);
	}
	// Set the Changed Rows - Clears the Table
	tblGames.setModel(model);
    }

    /**
     * Updates the Game Details in the Details Pane
     */
    protected void updateGameDetail() {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// Get the Selected Row
	int selectedRow = tblGames.getSelectedRow();
	if (selectedRow >= 0) {
	    // Get the Game Name from the Selected Row First Column
	    String gameName = (String) model.getValueAt(selectedRow, 0);
	    // Get the Game Details for the elected Game from the Server
	    GameDetails gameDetails = ServerService.getInstance().getGameDetails(gameName);
	    // Check that Game Name is Not Empty
	    if (gameName.isEmpty()) {
		// If the Game Name is Empty - Set to NO Name
		gameName = "[NO NAME]";
	    }
	    // Construct the Message
	    String detailsText = gameName + " (" + gameDetails.getGameStatus().toString() + ")\n\n"
		    + "Total Number Of Players: "
		    + Integer.toString(gameDetails.getTotalPlayers()) + "\n"
		    + "Number of Computerized Players: " + Integer.toString(gameDetails.getTotalComputerPlayers()) + "\n"
		    + "Number of Human Players\n(Joined Players/Total Human Players): " + Integer.toString(gameDetails.getJoinedHumans())
		    + "/" + Integer.toString(gameDetails.getTotalHumanPlayers()) + "\n";
	    // Check the Dice Roll Mode
	    if (gameDetails.isAutomaticDiceRoll()) {
		detailsText += "Using Automatic Dice Roll.";
	    } else {
		detailsText += "Using Manual Inserted Dice Roll.";
	    }
	    // Set the Text to the Game Details Label
	    lblGameDetails.setText(Utils.StringToHTML(detailsText));
	}
    }

    /**
     * Updates the Parameters from the Newly Created Game
     * @param gameName The Game Name
     * @param arrNewPlayers The New Players Array
     * @param isAutoDice The Dice Roll Mode
     */
    public void updateCreatedGame(String gameName, Integer humans, Integer computers, Boolean isAutoDice) {
	try {
	    // Start a Game - Usually in Wating State
	    ServerService.getInstance().startGame(gameName, humans, computers, isAutoDice);

	} catch (MonopolErrors ex) {
	    Utils.writeText(ex.getMessage());
	} finally {
	    // Update the Games Table
	    getMonopolyGames();
	    // Select the Newly created Game
	    selectGame(gameName);
	}
    }

    /**
     * Selects a Specific Game Row in the Game Table
     * @param gameName The Game to Select
     */
    private void selectGame(String gameName) {
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	Integer i = 0;
	Boolean found = false;
	while (found == false && i < model.getRowCount()) {
	    if (model.getValueAt(i, 0).equals(gameName)) {
		// Select the Row
		tblGames.setRowSelectionInterval(i, i);
		// We found our Game - End the Loop
		found = true;
	    }
	    // Increment the Counter
	    i++;
	}
    }

    /**
     * Check that the Game can Begin and if So Closes the Window
     * @param playerID The Player ID Retrieved from the Server
     * @param isFinished Is the Game Load Window has Finished its Functionality
     */
    protected void CloseWindow(String gameName, Integer playerID, boolean isFinished) {
	if (playerID != -1) {
	    // Save the Player ID
	    this.playerID = playerID;
	    // Check that the Game can Start
	    if (isFinished) {
		// Get the Selected Game Row Index
		int selectedRow = tblGames.getSelectedRow();
		// Verify that a row was selected
		if (selectedRow < 0) {
		    // No row was selected - select the first row
		    selectedRow = 0;
		}
		// Refresh the Game Details in the Table
		getMonopolyGames();
		// Re-Select the Selected Game Row
		tblGames.setRowSelectionInterval(selectedRow, selectedRow);
		// Check that all the Required players have joined
		if (checkPosibleStart()) {
		    // Stop Refreshing the Games
		    stopRefreshTask();
		    // Stop Trying to Join the Game
		    stopWaitingToJoin();
		    // Get All the Players in the Game
		    ServerService.getInstance().getPlayersDetails(gameName).toArray(arrPlayers);
		    // Close this Frame
		    this.dispose();
		    closeSignal.countDown();
		} else {
		    // Waiting for other Players to Join
		}
	    }
	} // Nothing Happend - Just Closed
	else {
	    // Stop Refreshing the Games
	    stopRefreshTask();
	    // We Stopped with an Error (No games were joined or created) - Set the Finished as False
	    finished = false;
	    // Close this Frame
	    this.dispose();
	    closeSignal.countDown();
	}
    }

    /**
     * Check the Availability of the Game to Start
     * @return True if the Game can Begin, False Otherwise
     */
    private boolean checkPosibleStart() {
	// Get the Table Model
	DefaultTableModel model = (DefaultTableModel) tblGames.getModel();
	// Get the Selected Row
	int selectedRow = tblGames.getSelectedRow();
	// Check that a Row is Selected
	if (selectedRow < 0) {
	    // No Row Selected - Select the First Row
	    selectedRow = 0;
	}
	// Get the Game Name from the Selected Row First Column
	String gameName = (String) model.getValueAt(selectedRow, 0);
	// Get the Game Details for the elected Game from the Server
	GameDetails gameDetails = ServerService.getInstance().getGameDetails(gameName);
	if (gameDetails.getTotalHumanPlayers() == gameDetails.getJoinedHumans()) {
	    // All the Human Players Have Joined
	    // The Game can Begin!
	    return true;
	} else {
	    // No All the Human Players have Joined
	    // Waiting for other Players to Join
	    return false;
	}
    }

    /**
     * Initialize the Create Game Form to its Default Values
     */
    private void clearCreateGameForm() {
	txtGameName.setText("");
	sldNumOfPlayers.setValue(2);
	sldNumOfHumans.setValue(2);
	chkAutoDice.setSelected(defDiceMode);
    }

    /**
     * Returns the Dice Mode
     * True if Using Automatic Dice Roll Mode
     * False if Using Manual Dice Roll Mode
     * @return The Automatic Dice Roll Mode
     */
    public Boolean getAutomaticDice() {
	return bAutoDice;
    }

    /**
     * Returns the Players Array Info
     * @return Players Array Info as Array of LoadInfo
     */
    public LoadInfo[] getPlayersArray() {
	return arrPlayers;
    }

    /**
     * Returns the Player ID in the Game
     * @return The Players ID in the Game
     */
    public Integer getPlayerID() {
	if (playerID != null) {
	    return playerID;
	} else {
	    // Return an Error Integer
	    return -1;
	}
    }

    /**
     * Returns the Player Name in the Game
     * @return The Player Name in the Game
     */
    public String getPlayerName() {
	if (playerName != null) {
	    return playerName;
	} else {
	    // Return an Empty Player Name
	    return null;
	}
    }

    /**
     * Checks if the Class is finished
     * @return The Finish variable
     */
    public Boolean getFinished() {
	return finished;
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnCreateStart;
    private javax.swing.JButton btnExit;
    private javax.swing.JButton btnSaveSettings;
    private javax.swing.JComboBox cbDefDiceMode;
    private javax.swing.JCheckBox chkAutoDice;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JLabel lblGameDetails;
    private javax.swing.JLabel lblHeader;
    private javax.swing.JLabel lblHumanTicks;
    private javax.swing.JPanel pnlGameDetails;
    private javax.swing.JSlider sldNumOfHumans;
    private javax.swing.JSlider sldNumOfPlayers;
    private javax.swing.JTabbedPane tabPanel;
    private javax.swing.JTable tblGames;
    private javax.swing.JTextField txtDefPlayerName;
    private javax.swing.JTextField txtGameName;
    private javax.swing.JTextField txtPlayerName;
    private javax.swing.JTextField txtServerName;
    private javax.swing.JTextField txtSrvPort;
    // End of variables declaration//GEN-END:variables

    /**
     * Gets the Selected Tab
     */
    private void addTabListener() {
	tabPanel.addChangeListener(new ChangeListener() {
	    // This method is called whenever the selected tab changes

	    public void stateChanged(ChangeEvent evt) {
		JTabbedPane pane = (JTabbedPane) evt.getSource();
		// Get current tab
		int selTab = pane.getSelectedIndex();
		if (selTab == 0) {
		    // The Join Game is Selected
		    btnCreateStart.setText(JOIN_GAME);
		} else if (selTab == 1) {
		    // The Create Game is Selected
		    btnCreateStart.setText(CREATE_GAME);
		    clearCreateGameForm();
		}
	    }
	});
    }

    /**
     *  Table Selection Listener
     */
    class TableListSelectionHandler implements ListSelectionListener {

	public void valueChanged(ListSelectionEvent e) {
	    ListSelectionModel lsm = (ListSelectionModel) e.getSource();
	    if (!lsm.getValueIsAdjusting()) {
		updateGameDetail();
	    }
	}
    }
}

class WaitForGameToStart extends TimerTask {

    private String gameName;
    private Integer playerID;
    private final GameLoaderFrame gameInstance;

    public WaitForGameToStart(GameLoaderFrame instance, String gameName, Integer playerID) {
	this.gameInstance = instance;
	this.gameName = gameName;
	this.playerID = playerID;
    }

    @Override
    public void run() {
	gameInstance.CloseWindow(gameName, playerID, true);
    }
}
